package fusion;

import handler.DeformationPoint;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import deformation.Deformation;
import deformedGrid.painter.DeformationPainter;


public class LinearCombination {
	private int numGridPointsX;
	private int numGridPointsY;
	public final int width;
	public final int height;
	private DeformationPainter deformationPainter1;
	/**
	 * @return the deformationPainter1
	 */
	public DeformationPainter getDeformationPainter1() {
		return deformationPainter1;
	}


	public void setImage1(BufferedImage image1) {
		this.deformationPainter1 = new DeformationPainter(numGridPointsX, numGridPointsY, image1);
	}
	
	public void setImage2(BufferedImage image2) {
		this.deformationPainter2 = new DeformationPainter(numGridPointsX, numGridPointsY, image2);
	}
	
	public void setNumGridPoints(int x, int y){
		if (x == this.numGridPointsX && y == this.numGridPointsY) {
			return;
		}
		this.numGridPointsX = x;
		this.numGridPointsY = y;
		this.deformationPainter1 = new DeformationPainter(numGridPointsX, numGridPointsY,this.deformationPainter1.width,this.deformationPainter1.height, this.deformationPainter1.getSrcImageRGB());
		this.deformationPainter2 = new DeformationPainter(numGridPointsX, numGridPointsY,this.deformationPainter2.width,this.deformationPainter2.height, this.deformationPainter2.getSrcImageRGB());
	}

	/**
	 * @return the deformationPainter2
	 */
	public DeformationPainter getDeformationPainter2() {
		return deformationPainter2;
	}




	private DeformationPainter deformationPainter2;
	public LinearCombination(int numGridPointsX, int numGridPointsY,
			int[] rgb1, int[] rgb2, int width, int height) {
		if (rgb1.length != rgb2.length) {
			System.err.println("rgb1 and rgb2 have different sizes");
		}
		this.numGridPointsX = numGridPointsX;
		this.numGridPointsY = numGridPointsY;
		this.width = width;
		this.height = height;
		deformationPainter1 = new DeformationPainter(numGridPointsX, numGridPointsY, width, height, rgb1);
		deformationPainter2 = new DeformationPainter(numGridPointsX, numGridPointsY, width, height, rgb2);
	}
	
	public LinearCombination(int numGridPointsX, int numGridPointsY,
			BufferedImage image1, BufferedImage image2) {
		this.numGridPointsX = numGridPointsX;
		this.numGridPointsY = numGridPointsY;
		this.width = image1.getWidth();
		this.height = image1.getHeight();
		deformationPainter1 = new DeformationPainter(numGridPointsX, numGridPointsY, image1);
		deformationPainter2 = new DeformationPainter(numGridPointsX, numGridPointsY, image2);
	}
	
	
	
	/**
	 * moved Points are ignored and overwritten
	 * @param defo1
	 * @param defo2
	 */
	public void setDeformations(Deformation defo1, Deformation defo2){
		if (defo1.getHandler().size() != defo1.getHandler().size()) {
			System.err.println("defo1 and defo1 have different sizes BasePoints");
		}
		deformationPainter1.setDeformation(defo1);
		deformationPainter2.setDeformation(defo2);
	}
	
	public BufferedImage getfuseImage(double factor, Rectangle rec){
		int[] rgb = fuse(factor, rec);
		BufferedImage image = new BufferedImage( rec.width, rec.height, BufferedImage.TYPE_INT_ARGB);	
		image.setRGB(0, 0,  rec.width, rec.height, rgb, 0, rec.width);
		return image;
	}
	
	public BufferedImage getfuseImage(double factor){
		int[] rgb = fuse(factor);
		BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB);	
		image.setRGB(0, 0,  width, height, rgb, 0, width);
		return image;
	}
	
	public Image getfuseImage(double factor, double color_factor, Rectangle rec) {
		int[] rgb = fuse(factor,color_factor, rec);
		BufferedImage image = new BufferedImage( rec.width, rec.height, BufferedImage.TYPE_INT_ARGB);	
		image.setRGB(0, 0,  rec.width, rec.height, rgb, 0, rec.width);
		return image;
	}
	

	public int[] fuse(double factor){
		DeformationPoint[] basePoints1 = deformationPainter1.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] basePoints2 = deformationPainter2.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] fusedBasePoints = new DeformationPoint[basePoints1.length];
		for (int i = 0; i < fusedBasePoints.length; i++) {
			fusedBasePoints[i] = new DeformationPoint((1-factor)*basePoints1[i].x +(factor)*basePoints2[i].x, (1-factor)*basePoints1[i].y +(factor)*basePoints2[i].y);
		}
		deformationPainter1.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		deformationPainter2.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		
		int[] rgb1 = deformationPainter1.getRGB();
		int[] rgb2 = deformationPainter2.getRGB();
		return combine(rgb1, rgb2, factor);
	}
	
	
	public int[] fuse(double factor, Rectangle rec){
		DeformationPoint[] basePoints1 = deformationPainter1.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] basePoints2 = deformationPainter2.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] fusedBasePoints = new DeformationPoint[basePoints1.length];
		for (int i = 0; i < fusedBasePoints.length; i++) {
			fusedBasePoints[i] = new DeformationPoint((1-factor)*basePoints1[i].x +(factor)*basePoints2[i].x, (1-factor)*basePoints1[i].y +(factor)*basePoints2[i].y);
		}
		deformationPainter1.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		deformationPainter2.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		
		int[] rgb1 = deformationPainter1.getRGB(rec);
		int[] rgb2 = deformationPainter2.getRGB(rec);
		return combine(rgb1, rgb2, factor);
	}
	
	public int[] fuse(double factor, double color_factor, Rectangle rec){
		DeformationPoint[] basePoints1 = deformationPainter1.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] basePoints2 = deformationPainter2.getDeformation().getHandler().getBasePointsArray();
		DeformationPoint[] fusedBasePoints = new DeformationPoint[basePoints1.length];
		for (int i = 0; i < fusedBasePoints.length; i++) {
			fusedBasePoints[i] = new DeformationPoint((1-factor)*basePoints1[i].x +(factor)*basePoints2[i].x, (1-factor)*basePoints1[i].y +(factor)*basePoints2[i].y);
		}
		deformationPainter1.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		deformationPainter2.getDeformation().getHandler().elementalMoveAll(fusedBasePoints);
		
		int[] rgb1 = deformationPainter1.getRGB(rec);
		int[] rgb2 = deformationPainter2.getRGB(rec);
		return combine(rgb1, rgb2, color_factor);
	}
	
	
	
	/**
	 * 
	 * @param rgb1
	 * @param rgb2
	 * @param faktor
	 * @return = rgb1*(1-factor) + rgb2*(factor)
	 */
	static int[] combine(int[] rgb1, int[] rgb2, double factor){
		int[] rgb = new int[rgb1.length]; 
		int r;
		int g;
		int b;
		for (int i = 0; i < rgb.length; i++) {
			r = (int) (((rgb1[i] >> 16) & 0xFF)*(1-factor)+
					((rgb2[i] >> 16) & 0xFF)*factor);
			g = (int) (((rgb1[i] >> 8) & 0xFF)*(1-factor)+
					((rgb2[i] >> 8) & 0xFF)*factor);
			b = (int) (((rgb1[i] >> 0) & 0xFF)*(1-factor)+
					((rgb2[i] >> 0) & 0xFF)*factor);
			r = r <255 ? r : 255;
			r = r >=0 ? r : 0;
			g = g <255 ? g : 255;
			g = g >=0 ? g : 0;
			b = b <255 ? b : 255;
			b = b >=0 ? b : 0;
			rgb[i] = ((255 & 0xFF) << 24) |  //alpha is 255
			        ((r & 0xFF) << 16) |
			        ((g & 0xFF) << 8)  |
			        ((b & 0xFF) << 0);
		}
		
		return rgb;
	}




}
